/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package main.CrossValidation;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import main.KBProcess.Element;
import main.KBProcess.KnowledgeBaseDocument;
import main.NER.Trie.CandidateExtractor;
import main.NER.Trie.KBTrie;
import main.NER.Trie.NER_Candidate;
import main.Ontology.ElementOntologySet;
import main.Weighting.EvaluationParams;

/**
 *
 * @author Isaac Osesina
 */
public class WorkSpace implements Serializable, Cloneable{


    public static List<NER_Candidate> getEvaluation(CandidateExtractor solver, KnowledgeBaseDocument doc, String weightingMethod) {
        return solve(solver, doc.getDocText(), weightingMethod);
    }

    public static List<NER_Candidate> getEvaluation(CandidateExtractor solver, List<KnowledgeBaseDocument> docs, String weightingMethod) {
        List<NER_Candidate> candidates = null;
        if(docs != null) {
            candidates = new ArrayList<NER_Candidate>();
            List<Element>  entities = new ArrayList<Element>();
            for(KnowledgeBaseDocument doc:docs) {
                List<NER_Candidate> solve = solve(solver, doc.getDocText(), weightingMethod);
                if(solve != null) {
                    candidates.addAll(solve);
                }
                entities.addAll(doc.getEntities());
            }            
        }
        return candidates;
    }


    public static List<NER_Candidate> getCandidates(CandidateExtractor solver, KnowledgeBaseDocument doc, String weightingMethod) {
        return solve(solver, doc.getDocText(), weightingMethod);
    }

    public static List<NER_Candidate> solve(CandidateExtractor solver, String text, String weightingMethod) {
        if(solver != null && weightingMethod != null) {
            return solver.extractCandidates(weightingMethod, weightingMethod);
        }
        return null;
    }

    private static class ScoreKeep {
        Integer count = 0, correct = 0, possibleCount = 0;

        public ScoreKeep(Integer possibleCount) {
            this.possibleCount = possibleCount;
        }

        public double getPrecision() {
            return count > 0 ? correct / count : count;
        }

        public double getRecall() {
            return possibleCount > 0 ? correct / possibleCount : possibleCount;
        }
    }

    public static class ScoreKeeper{
        List<Double> values;

        public ScoreKeeper() {
            values = new ArrayList<Double>();
        }

        public ScoreKeeper(double v) {
            values = new ArrayList<Double>();
            values.add(v);
        }

        public void addValue(double v) {
            values.add(v);
        }

        public double getAverage() {
            if(values != null) {
                double sumX = 0;
                int count = 0;
                for (int i = 1; i < values.size(); i++) {
                    if(values.get(i) != null){
                        sumX += values.get(i);
                        count++;
                    }
                }
                return count>0 ? sumX / count: count;
            }
            return 0;
        }
    }


    public static Map<String, Map<ElementOntologySet, EvaluationParams>> getEvaluations(
                                                    Map<String, List<NER_Candidate>> weightMethod_candidateList,
                                                    List<Element> entityList ) {
        Map<String, Map<ElementOntologySet, EvaluationParams>> result = null;
        if(weightMethod_candidateList != null) {
            result = new HashMap<String, Map<ElementOntologySet, EvaluationParams>>();
            for(String weightMethod:weightMethod_candidateList.keySet()) {
                Map<ElementOntologySet, EvaluationParams> evaluations = getEvaluations(weightMethod_candidateList.get(weightMethod), entityList);
                if(evaluations != null) {
                    result.put(weightMethod, evaluations);
                }
            }
        }
        return result;
    }

    public static Map<ElementOntologySet, EvaluationParams> getEvaluations(List<NER_Candidate> candidateList, List<Element> entityList ) {
        Map<ElementOntologySet, EvaluationParams> out = new HashMap<ElementOntologySet, EvaluationParams>();
        Map<ElementOntologySet, Integer> entityTypeCount = labelsClassification(entityList);
        Map<ElementOntologySet, ScoreKeep> tmp = new HashMap<ElementOntologySet, ScoreKeep>();
        for (NER_Candidate c : candidateList) {
            if (c != null) {
                ElementOntologySet branchID = c.getOntologies();
                ScoreKeep score = tmp.get(branchID);
                if(score == null) {
                      score = new ScoreKeep(entityTypeCount.get(branchID));
                      tmp.put(branchID, score);
                }
                score.count++;
                if(c.isCorrect()) {
                    score.correct++;
                }
            }
        }
        for(ElementOntologySet branchId:tmp.keySet()) {
            ScoreKeep score = tmp.get(branchId);
            out.put(branchId, new EvaluationParams(score.getPrecision(),score.getRecall()));
        }
        return out;
    }

    private static Map<ElementOntologySet, Integer> labelsClassification(List<Element> entityList) {
        Map<ElementOntologySet, Integer> entityTypeCount = new HashMap<ElementOntologySet, Integer>();
            for (Element e : entityList) {
            if (e != null) {
                ElementOntologySet branchID = e.getOntologies();
                Integer score = entityTypeCount.get(branchID);
                if(score == null) {
                      score = 0;
                      entityTypeCount.put(branchID, score);
                }
                score++;                
            }
        }
        return entityTypeCount;
    }

    public static Map<ElementOntologySet, String> getBestWeightingMethods(List<Map<String, Map<ElementOntologySet, EvaluationParams>>> weightMethod_BranchID_evaluations) {
        Map<String, Map<ElementOntologySet, ScoreKeeper>> result = null;
        if(weightMethod_BranchID_evaluations != null) {
            result = new HashMap<String, Map<ElementOntologySet, ScoreKeeper>>();
            for(Map<String, Map<ElementOntologySet, EvaluationParams>> evalMap:weightMethod_BranchID_evaluations) {
                if(evalMap != null) {
                    for(String weightMethod:evalMap.keySet()) {
                        Map<ElementOntologySet, EvaluationParams> eval = evalMap.get(weightMethod);
                        if(eval != null) {
                            for(ElementOntologySet branchID:eval.keySet()) {
                                EvaluationParams params = eval.get(branchID);
                                if(params != null) {
                                    if(result.get(weightMethod) == null) {
                                        result.put(weightMethod, new HashMap<ElementOntologySet, ScoreKeeper>());
                                    }
                                    if(result.get(weightMethod).get(branchID) == null) {
                                        result.get(weightMethod).put(branchID, new ScoreKeeper());
                                    }
                                    result.get(weightMethod).get(branchID).addValue(params.getfMeasure());
                                }
                            }
                        }
                    }
                }
            }
        }
        return getBestWeightingMethods_ScoreKeeper(result);
    }


    private static Map<ElementOntologySet, String> getBestWeightingMethods_ScoreKeeper(Map<String, Map<ElementOntologySet, ScoreKeeper>> evals) {
        Map<ElementOntologySet, String> out = null;
        if(evals != null) {
            out = new HashMap<ElementOntologySet, String>();
            Map<String, ScoreKeeper> tmpeVal = new HashMap<String, ScoreKeeper>();
            for(String weightMethod:evals.keySet()) {
                Map<ElementOntologySet, ScoreKeeper> branchIDeVal = evals.get(weightMethod);
                if(branchIDeVal != null) {
                    for(ElementOntologySet branchID:branchIDeVal.keySet()) {
                        ScoreKeeper neweVal = branchIDeVal.get(branchID);
                        if(neweVal == null)
                            continue;
                        ScoreKeeper oldeVal = tmpeVal.get(branchID);
                        if( oldeVal == null || neweVal.getAverage()>oldeVal.getAverage() ) {
                            oldeVal = neweVal;
                            out.put(branchID, weightMethod);
                        }
                    }
                }
            }
        }
        return out;
    }


    public static Map<String, String> getBestWeightingMethods(Map<String, Map<String, EvaluationParams>> evals) {
        Map<String, String> out = null;
        if(evals != null) {
            out = new HashMap<String, String>();
            Map<String, EvaluationParams> tmpeVal = new HashMap<String, EvaluationParams>();
            for(String weightMethod:evals.keySet()) {
                Map<String, EvaluationParams> branchIDeVal = evals.get(weightMethod);
                if(branchIDeVal != null) {
                    for(String branchID:branchIDeVal.keySet()) {
                        EvaluationParams neweVal = branchIDeVal.get(branchID);
                        if(neweVal == null)
                            continue;
                        EvaluationParams oldeVal = tmpeVal.get(branchID);
                        if( oldeVal == null || neweVal.getfMeasure()>oldeVal.getfMeasure() ) {
                            oldeVal = neweVal;
                            out.put(branchID, weightMethod);
                        }                        
                    }
                }
            }
        }
        return out;
    }


}
